﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Communergy.Common;
using CommunergyLogicTests.MockObjects;
using Communergy.UnitTesting;


namespace CommunergyLogicTests
{
    public class MockRepositoryFactory : IRepositoryFactory
    {

        MockUnitOfWork unitOfWork;

        public MockRepositoryFactory(): this(1, DateTime.Now.AddMonths(-1), DateTime.Now)
        {

        }

        public MockRepositoryFactory(int metersToCreate, DateTime dateFrom, DateTime dateTo)
        {
            unitOfWork = new MockUnitOfWork();

            for (int i = 0; i < metersToCreate; i++)
            {
                var meterId = UnitTestHelper.RandomString(10);
                DateTime thisDate = dateFrom;
                int interval = 6;
                while (thisDate < dateTo)
                {
                    MockRealtime mockRealtime = new MockRealtime();
                    mockRealtime.MeterId = meterId;
                    var reading = UnitTestHelper.RandomInt(100, 1000);
                    mockRealtime.Watts = reading;
                    var joules = reading * interval;
                    mockRealtime.Joules = joules;
                    mockRealtime.ReadingDateTime = thisDate;
                    thisDate = thisDate.AddSeconds(interval);

                    unitOfWork.RealtimeCommitted.Add(mockRealtime);
                }

                UpdateAggregates(meterId);
            }

        }

        private void UpdateAggregates(string meterId)
        {
            UpdateHoursFromRealtime(meterId);
            UpdateDaysFromHours(meterId);
            UpdateMonthsFromDays(meterId);
        }

        private void UpdateMonthsFromDays(string meterId)
        {
            var months = (from d in unitOfWork.DailyCommitted
                          group d by new { d.ReadingDateTime.Year, d.ReadingDateTime.Month } into rolled
                          select new MockHistorical
                          {
                              MeterId = meterId,
                              ReadingDateTime = new DateTime(rolled.Key.Year, rolled.Key.Month, 1),
                              KWh = ((decimal)rolled.Sum(mh => mh.KWh))
                          }).ToList();
            unitOfWork.MonthlyCommitted = unitOfWork.MonthlyCommitted.Union(months).ToList() ;
        }

        private void UpdateDaysFromHours(string meterId)
        {
            var days = (from h in unitOfWork.HourlyCommitted
                        group h by new { h.ReadingDateTime.Year, h.ReadingDateTime.Month, h.ReadingDateTime.Day } into rolled
                        select new MockHistorical
                        {
                            MeterId = meterId,
                            ReadingDateTime = new DateTime(rolled.Key.Year, rolled.Key.Month, rolled.Key.Day, 0, 0, 0),
                            KWh = ((decimal)rolled.Sum(mh => mh.KWh))
                        }).ToList();
            unitOfWork.DailyCommitted = unitOfWork.DailyCommitted.Union(days).ToList();
        }

        private void UpdateHoursFromRealtime(string meterId)
        {
            var hours = (from r in unitOfWork.RealtimeCommitted
                         group r by new { r.ReadingDateTime.Year, r.ReadingDateTime.Month, r.ReadingDateTime.Day, r.ReadingDateTime.Hour } into rolled
                         select new MockHistorical
                         {
                             MeterId = meterId,
                             ReadingDateTime = new DateTime(rolled.Key.Year, rolled.Key.Month, rolled.Key.Day, rolled.Key.Hour, 0, 0),
                             KWh = ((decimal)rolled.Sum(mh => mh.Joules)) / 3600000
                         }).ToList();
            unitOfWork.HourlyCommitted = unitOfWork.HourlyCommitted.Union(hours).ToList();
        }

        #region IRepositoryFactory Members

        public IUnitOfWork CreateUnitOfWork()
        {
            return unitOfWork;
        }

        public IHistoricRepository CreateHistoricRepository(IUnitOfWork unitOfWork)
        {
            return new MockHistoricRepository(unitOfWork);
        }

        public IMeterRepository CreateMeterRepository(IUnitOfWork unitOfWork)
        {
            return new MockMeterRepository(unitOfWork);
        }

        public IRealtimeRepository CreateRealtimeRepository(IUnitOfWork unitOfWork)
        {
            return new MockRealtimeRepository(unitOfWork);
        }

        #endregion

       
    }
}
